package com.fingard.dsp.bank.directbank.cgbunion01;

import cfca.sadk.algorithm.sm2.SM2PublicKey;
import cfca.sadk.cgb.toolkit.BASE64Toolkit;
import cfca.sadk.cgb.toolkit.SM2Toolkit;
import com.alibaba.fastjson.JSONObject;
import com.fingard.common.utils.json.JSONUtils;
import com.fingard.constant.Format;
import com.fingard.crypto.DigestHelper;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.dsp.bank.directbank.cgbunion01.util.*;
import com.fingard.net.WebRequest;
import com.fingard.text.StringHelper;
import com.fingard.util.DateHelper;
import org.apache.commons.lang.RandomStringUtils;

import java.util.*;

public class CGBUnion01Base extends DirectBase {
    protected String getCharset() {
        return getBankConfig().getCharset("UTF-8");
    }
    public HashMap<String, String> getOpenid(String p_appId, String p_appSecret, String p_code) {
        HashMap<String, String> retHash = new HashMap<String, String>();

        String respCode = "";
        String respInfo = "";

        String tmpUrl = bankFront.getUrl("access_token");
        if (StringHelper.isNullOrEmpty(tmpUrl)) {
            respCode = "-1";
            respInfo = "未设置“通过code换取网页授权access_token”的地址,请检查BankFront.xml相关配置!";
        } else {
            tmpUrl = tmpUrl + "?appid=" + p_appId + "&secret=" + p_appSecret + "&code=" + p_code
                    + "&grant_type=authorization_code";
            WriteBankLogStep2(tmpUrl);

            WebRequest tmpWebRequest = new WebRequest(tmpUrl);
            String[] tmpRet = tmpWebRequest.upload(null, getCharset());
            if (tmpRet[0].length() == 0) {
                WriteBankLogStep3(tmpRet[1]);

                if (tmpRet[1].startsWith("{")) {
                    retHash = JSONUtils.json2Map(tmpRet[1]);
                    respCode = "0";
                } else {
                    respCode = "-1";
                    respInfo = tmpRet[1];
                }
            } else {
                respCode = "-1";
                respInfo = tmpRet[1];
                WriteBankLogLn(tmpRet[0] + "\r\n" + tmpRet[1]);
            }
        }

        retHash.put("RespCode", respCode);
        retHash.put("RespInfo", respInfo);

        return retHash;
    }
    public String get_nonce_str() throws Exception{
        String time_stamp = DateHelper.getSecsFrom1970();
        //随机字符串 String(32)
        Random random=new Random();
        long randLong = random.nextLong();
        randLong = random.nextLong();
        String nonce_str = time_stamp+String.format("%20d", randLong);
        nonce_str = DigestHelper.cryptoMD5RetHexStr(nonce_str.getBytes());
        return nonce_str;
    }
    public static String randomStr() {
        return UUID.randomUUID().toString().replace("-", "").toUpperCase();
    }
    public HashMap<String, String> buildHeaderParam(String serviceName,ActSetItem actItem){
        HashMap<String, String> retHash = new HashMap<String, String>();
        retHash.put("version","1.0.0");
        retHash.put("instId",actItem.corpCode);
        retHash.put("appId",actItem.appIdMap.get("appId"));
        retHash.put("productCode","payService");
        retHash.put("tradeCode",serviceName);
        retHash.put("requestTime",Format.DateTime14Format.format(new Date()));
        retHash.put("senderSN",randomStr());
        retHash.put("encryptType","SM2");
        retHash.put("reserve","");
        return retHash;
    }
    public String send(JSONObject order, String serviceName,ActSetItem actItem) throws Exception {
        try {
            String utf = getCharset();
            String requestJsonReport = JSONObject.toJSONString(order);
            WriteBankLogLn("original request report---->{}"+requestJsonReport);
            RandomStringUtils rs = new RandomStringUtils();
            String verifyChars = "123457890abcdefghijklmnopqrstuvwxyz";
            String encryptKey = rs.random(16, verifyChars).toUpperCase();
            String requestEncryptJson = SM4Utils.SM4EncryptData(encryptKey, requestJsonReport, utf);
            WriteBankLogLn("request report after encrypting---->encryptKey[{}]----->{}"+ encryptKey+"---"+requestEncryptJson);
            // 对原报文签名

            String requestSignatureJson = SM2SignUtils.signString(requestJsonReport, FileHelper.loadFileBytes(actItem.oppCertFilePath, actItem.ownKeyStorePath), utf);
            // 证书ID，使用公钥MD5值
            String certId = MD5Utils.getMD5(FileHelper.loadFileBytes(actItem.oppCertFilePath, actItem.webAPISercretKey));
            WriteBankLogLn("certId----->{}"+certId);
            WriteBankLogLn("request report after signing---->{}"+requestSignatureJson);

            // 对报文加密密钥加密，使用广发公钥进行加密
            String keyToEncry = SM2SignUtils.encryptString(FileHelper.loadFileBytes(actItem.oppCertFilePath, actItem.ownCertFilePath), encryptKey, utf);
            // http请求头创建
            Map<String, String> headerMap = buildHttpHeaderMap(certId, requestSignatureJson, keyToEncry);
            // 获取请求url
            String requestUrl = bankFront.getUrl(serviceName) + "/payService/" + serviceName + "/1.0.0";
            WriteBankLogLn("请求广发聚合地址："+requestUrl);
            // 发送请求到广发金融开放平台
            HttpResult result = HttpClientUtils.sendHttpPostWithCustomHeader(requestUrl, requestEncryptJson, headerMap);
            // 响应报文原文(为加密串)
            String responseJson = result.getResult();
            WriteBankLogLn("广发聚合返回原文："+responseJson);
            // 响应报文解密
            String responseDecryptJson = SM4Utils.SM4DecryptData(encryptKey, responseJson, utf);
            WriteBankLogLn("广发聚合返回报文："+responseDecryptJson);
            // 响应报文验签
            String responseSignature = result.getHeaderMap().get("signature");
            boolean veriyfyResult = SM2SignUtils.verifySignString(FileHelper.loadFileBytes(actItem.oppCertFilePath, actItem.ownCertFilePath), responseSignature, responseDecryptJson, utf);
            WriteBankLogLn("签名验证结果："+veriyfyResult);
            // 验签通过即返回解密后的报文
            return responseDecryptJson;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    private Map<String, String> buildHttpHeaderMap(String certId, String signature, String reportKeyBeEncrypted) {
        Map<String, String> headerMap = new HashMap<String, String>();
        headerMap.put("certId", certId);
        headerMap.put("signature", signature);
        headerMap.put("signType", "SM2");
        headerMap.put("Content-Type", "application/json;charset=UTF-8");
        headerMap.put("encryptType", "SM4");
        headerMap.put("encryptKey", reportKeyBeEncrypted);
        return headerMap;
    }

    public boolean verifySign(ActSetItem actItem, String sign, String plain) throws Exception{
        boolean result = false;
        try {
            //读取公钥
            SM2Toolkit sm2Tool = new SM2Toolkit();
            byte[] publiceByte = FileHelper.loadFileBytes(actItem.oppCertFilePath, actItem.ownCertFilePath);

            SM2PublicKey sm2MerPublicKey=(SM2PublicKey)sm2Tool.SM2BuildPublicKey(BASE64Toolkit.encode(publiceByte));

            //验证签名
            result=sm2Tool.SM2Verify(sm2MerPublicKey, plain.getBytes(getCharset()), BASE64Toolkit.decode(sign));

        } catch (Exception e) {
            throw e;
        }
        return result;
    }
}
